package com.ruoyi.crm.service.impl;

import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.DictUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.crm.domain.AssignRecord;
import com.ruoyi.crm.domain.Business;
import com.ruoyi.crm.domain.Clue;
import com.ruoyi.crm.mapper.BusinessMapper;
import com.ruoyi.crm.mapper.ClueMapper;
import com.ruoyi.crm.modules.quartz.RemindedService;
import com.ruoyi.crm.service.IAssignRecordService;
import com.ruoyi.crm.service.IClueService;
import com.ruoyi.crm.util.MybatisBatchUtils;
import lombok.extern.slf4j.Slf4j;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 线索Service业务层处理
 * 
 * @author ruoyi
 * @date 2022-05-31
 */
@Service
@Slf4j
public class ClueServiceImpl implements IClueService 
{
    @Resource
    private ClueMapper clueMapper;
    @Resource
    private BusinessMapper businessMapper;
    @Resource
    private IAssignRecordService assignRecordService;
    @Resource
    private KieContainer kieContainer;
    @Resource
    private MybatisBatchUtils mybatisBatchUtils;
    @Resource
    private RemindedService remindedService;

    @Value("${crm.remind.ahead-of-time:60m}")
    private Duration aheadOfTime;
    /**
     * 查询线索
     * 
     * @param id 线索主键
     * @return 线索
     */
    @Override
    public Clue selectClueById(Long id)
    {
        return clueMapper.selectClueById(id);
    }

    /**
     * 查询线索列表
     * 
     * @param clue 线索
     * @return 线索
     */
    @Override
    public List<Clue> selectClueList(Clue clue)
    {
        Long userId = SecurityUtils.getUserId();
        if(!SecurityUtils.isAdmin(userId)) {
            clue.setOwner(SecurityUtils.getUsername());
        }
        return clueMapper.selectClueList(clue);
    }

    /**
     * 新增线索
     * 
     * @param clue 线索
     * @return 结果
     */
    @Override
    public int insertClue(Clue clue)
    {
        clue.setCreateTime(DateUtils.getNowDate());
        return clueMapper.insertClue(clue);
    }

    /**
     * 修改线索
     * 
     * @param clue 线索
     * @return 结果
     */
    @Override
    public int updateClue(Clue clue)
    {
        if (!StringUtils.hasText(clue.getOwner())) {
            // 获取owenr
            AssignRecord assignRecord = new AssignRecord();
            assignRecord.setLatest(AssignRecord.LatestStatus.LATEST.getValue());
            assignRecord.setAssignId(clue.getId());
            List<AssignRecord> assignRecordList = assignRecordService.selectAssignRecordList(assignRecord);
            if (!assignRecordList.isEmpty()) {
                clue.setOwner(assignRecordList.get(0).getUserName());
            }
        }
        Date nextTime = clue.getNextTime();
        if(StringUtils.hasText(clue.getOwner()) && nextTime.after(new Date())) {
            LocalDateTime localDateTime = LocalDateTime.from(nextTime.toInstant().atZone(ZoneId.systemDefault()));
            LocalDateTime notifyTime = localDateTime.plusMinutes(-aheadOfTime.toMinutes());
            String format = notifyTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            Map<String, Object> userInfo = clueMapper.selectUserInfo(clue.getOwner());
            String phonenumber = (String) userInfo.get("phonenumber");
            log.debug("定时任务将在{}执行，通知{}, {}", format, clue.getOwner(), phonenumber);

            remindedService.createJob(notifyTime, "task:clue:" + clue.getId(),  phonenumber, "定时提醒线索【" + clue.getId() + "】");
        }
        clue.setUpdateTime(DateUtils.getNowDate());
        return clueMapper.updateClue(clue);
    }

    /**
     * 批量删除线索
     * 
     * @param ids 需要删除的线索主键
     * @return 结果
     */
    @Override
    public int deleteClueByIds(Long[] ids)
    {
        return mybatisBatchUtils.batchUpdateOrInsert(Arrays.asList(ids), ClueMapper.class,
                (id, mapper) -> mapper.deleteClueById(id));
    }

    /**
     * 删除线索信息
     * 
     * @param id 线索主键
     * @return 结果
     */
    @Override
    public int deleteClueById(Long id)
    {
        return clueMapper.deleteClueById(id);
    }

    /**
     * 转伪线索
     * @param id
     * @return
     */
    @Override
    @Transactional
    public int fakeClue(Long id) {
        Clue clue = clueMapper.selectClueById(id);
        if(clue.getFalseCount() >= Clue.FALSE_COUNT_LIMIT) {
            return 0;
        } else {
            assignRecordService.updateAssignRecord(id, AssignRecord.Type.CLUE, AssignRecord.LatestStatus.STALE);

            clue.setFalseCount(clue.getFalseCount() + 1);
            clue.setStatus(Clue.Status.FAKE.getValue());
            clue.setUpdateTime(new Date());
            clue.setUpdateBy(SecurityUtils.getUsername());
            return clueMapper.updateClue(clue);
        }
    }
    /**
     * 重新捞取
     * @param clueIds
     * @return
     */
    @Transactional
    @Override
    public int restoreClue(Long[] clueIds) {

       /* Clue clue = clueMapper.selectClueById(clueId);
        clue.setStatus(Clue.Status.NEW.getValue());
        clue.setUpdateTime(new Date());
        clue.setUpdateBy(SecurityUtils.getUsername());
        return clueMapper.updateClue(clue);*/
        for (Long clueId : clueIds) {
            // 分配线索给当前用户
            AssignRecord assignRecord = new AssignRecord();
            assignRecord.setType(AssignRecord.Type.CLUE.name());
            assignRecord.setAssignId(clueId);
            assignRecord.setUserId(SecurityUtils.getUserId());
            assignRecord.setDeptId(SecurityUtils.getDeptId());
            assignRecord.setCreateTime(new Date());
            assignRecord.setUserName(SecurityUtils.getUsername());
            assignRecordService.insertAssignRecord(assignRecord);
        }
        return clueIds.length;
    }

    /**
     * 转商机
     * @param clueId
     * @return
     */
    @Transactional
    @Override
    public int transform2Business(Long clueId) {
        // 更新线索状态
        Clue clue = clueMapper.selectClueById(clueId);
        clue.setStatus(Clue.Status.TO_BUSINESS.getValue());
        clue.setUpdateBy(SecurityUtils.getUsername());
        clue.setUpdateTime(new Date());
        clueMapper.updateClue(clue);
        // 插入商机
        Business business = new Business();
        BeanUtils.copyProperties(clue, business);
        business.setClueId(clue.getId());
        business.setCreateBy(SecurityUtils.getUsername());
        business.setCreateTime(new Date());
        business.setStatus(Clue.Status.NEW.getValue());
        businessMapper.insertBusiness(business);
        // 分配商机给当前用户
        AssignRecord assignRecord = new AssignRecord();
        assignRecord.setType(AssignRecord.Type.BUSINESS.name());
        assignRecord.setAssignId(business.getId());
        assignRecord.setUserId(SecurityUtils.getUserId());
        assignRecord.setDeptId(SecurityUtils.getDeptId());
        assignRecord.setCreateTime(new Date());
        assignRecord.setUserName(SecurityUtils.getUsername());
        return assignRecordService.insertAssignRecord(assignRecord);
    }

    /**
     * 插入线索，并根据规则引擎配置自动分配归属用户
     * @param clues
     * @return
     */
    @Override
    @Transactional
    public int insertClues(List<Clue> clues) {
        int sum = 0;
        KieSession kieSession = kieContainer.newKieSession();
        for (Clue clue : clues) {
            // 调用规则引擎，自动分配归属人
            kieSession.insert(clue);
            kieSession.fireAllRules();

            clue.setChannel(DictUtils.getDictValue("clues_item", clue.getChannel()));
            clue.setSubject(DictUtils.getDictValue("course_subject", clue.getSubject()));
            clue.setLevel(DictUtils.getDictValue("clues_level", clue.getLevel()));
            clue.setSex(DictUtils.getDictValue("sys_user_sex", clue.getSex()));
            clue.setStatus(Clue.Status.NEW.getValue());
            sum += this.insertClue(clue);

            // 分配线索给指定用户
            AssignRecord assignRecord = new AssignRecord();
            assignRecord.setType(AssignRecord.Type.CLUE.name());
            assignRecord.setAssignId(clue.getId());
            assignRecord.setCreateTime(new Date());
            setUserInfo(assignRecord, clue.getOwner());
            assignRecordService.insertAssignRecord(assignRecord);
        }
        kieSession.destroy();
        return sum;
    }

    private void setUserInfo(AssignRecord assignRecord, String owner) {
        Map<String, Object> userInfo = getUserInfo(owner);
        assignRecord.setUserId((Long) userInfo.get("user_id"));
        assignRecord.setDeptId((Long) userInfo.get("dept_id"));
        assignRecord.setUserName(owner);
    }

    /**
     * 根据用户名获取id和dept_id，手动缓存查询
     * @param userName
     * @return
     */
    public Map<String, Object> getUserInfo(String userName) {
        final String key = "crm:clue:userInfo:" + userName;
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        Map<String, Object> cacheMap = redisCache.getCacheMap(key);
        if(cacheMap.isEmpty()) {
            cacheMap = clueMapper.selectUserInfo(userName);
            redisCache.setCacheMap(key, cacheMap);
            redisCache.expire(key, 5, TimeUnit.MINUTES);
        }
        return cacheMap;
    }

    @Override
    public List<Clue> selectTimeoutClueList() {
        return clueMapper.selectTimeoutClueList();
    }
}
